﻿// Copyright 2009 John Diss (www.newgrove.com)
/*
 * This license governs use of the accompanying software. If you use the software, you
 * accept this license. If you do not accept the license, do not use the software.
 * 
 * 1. Definitions
 * The terms "reproduce," "reproduction," "derivative works," and "distribution" have the
 * same meaning here as under U.S. copyright law.
 * A "contribution" is the original software, or any additions or changes to the software.
 * A "contributor" is any person that distributes its contribution under this license.
 * "Licensed patents" are a contributor's patent claims that read directly on its contribution.
 * 
 * 2. Grant of Rights
 * (A) Copyright Grant- Subject to the terms of this license, including the license conditions 
 *     and limitations in section 3, each contributor grants you a non-exclusive, worldwide, 
 *     royalty-free copyright license to reproduce its contribution, prepare derivative works 
 *     of its contribution, and distribute its contribution or any derivative works that you create.
 * (B) Patent Grant- Subject to the terms of this license, including the license conditions and 
 *     limitations in section 3, each contributor grants you a non-exclusive, worldwide, royalty-free 
 *     license under its licensed patents to make, have made, use, sell, offer for sale, import, 
 *     and/or otherwise dispose of its contribution in the software or derivative works of the 
 *     contribution in the software.
 * 
 * 3. Conditions and Limitations
 * (A) No Trademark License- This license does not grant you rights to use any contributors' 
 *     name, logo, or trademarks.
 * (B) If you bring a patent claim against any contributor over patents that you claim are 
 *     infringed by the software, your patent license from such contributor to the software 
 *     ends automatically.
 * (C) If you distribute any portion of the software, you must retain all copyright, patent, 
 *     trademark, and attribution notices that are present in the software.
 * (D) If you distribute any portion of the software in source code form, you may do so only under 
 *     this license by including a complete copy of this license with your distribution. If you 
 *     distribute any portion of the software in compiled or object code form, you may only do so 
 *     under a license that complies with this license.
 * (E) The software is licensed "as-is." You bear the risk of using it. The contributors give no 
 *     express warranties, guarantees or conditions. You may have additional consumer rights under 
 *     your local laws which this license cannot change. To the extent permitted under your local laws, 
 *     the contributors exclude the implied warranties of merchantability, fitness for a particular 
 *     purpose and non-infringement.
 * 
 */
using System;
using System.Collections.Generic;
using NPack.Numeric.Interfaces;

namespace NPack.Numeric
{
    [Serializable]
    public struct Real<T> : IArithmetic<T>, INumeric<T>, IArithmetic<Real<T>>, INumeric<Real<T>>
    {
        public readonly T Value;

        public Real(T val)
        {
            Value = val;
        }

        public Real(Int32 i)
        {
            Value = NumericOperations<T, T, T, Real<T>>.FromInt32(i);
        }

        public Real(Int64 l)
        {
            Value = NumericOperations<T, T, T, Real<T>>.FromInt64(l);
        }

        public Real(Single s)
        {
            Value = NumericOperations<T, T, T, Real<T>>.FromSingle(s);
        }

        public Real(Double d)
        {
            Value = NumericOperations<T, T, T, Real<T>>.FromDouble(d);
        }

        public Real(Decimal d)
        {
            Value = NumericOperations<T, T, T, Real<T>>.FromDecimal(d);
        }

        #region IArithmetic<Real<T>> Members

        Real<T> INegatable<Real<T>>.Negative()
        {
            return Value * new Real<T>(-1.0);
        }

        public Real<T> Abs()
        {
            return NumericOperations<T, T, T, Real<T>>.Abs(Value);
        }

        public Real<T> Sqrt()
        {
            return NumericOperations<T, T, T, Real<T>>.Sqrt(Value);
        }

        Real<T> IHasZero<Real<T>>.Zero
        {
            get { return new Real<T>(0.0); }
        }

        public Real<T> Subtract(Real<T> b)
        {
            return new Real<T>(NumericOperations<T, T, T, Real<T>>.Sub(Value, b.Value));
        }
        public Real<T> Add(Real<T> b)
        {
            return new Real<T>(NumericOperations<T, T, T, Real<T>>.Add(Value, b.Value));
        }

        public Real<T> Divide(Real<T> b)
        {
            return new Real<T>(NumericOperations<T, T, T, Real<T>>.Div(Value, b.Value));
        }

        public Real<T> Multiply(Real<T> b)
        {
            return new Real<T>(NumericOperations<T, T, T, Real<T>>.Mul(Value, b.Value));
        }




        Real<T> IHasOne<Real<T>>.One
        {
            get { return new Real<T>(1.0); }
        }



        #endregion

        #region IArithmetic<T> Members

        public T Negative()
        {
            return Value * new Real<T>(-1.0);
        }

        public T Subtract(T b)
        {
            return NumericOperations<T, T, T, Real<T>>.Sub(Value, b);
        }

        public T Zero
        {
            get { return new Real<T>(0.0); }
        }

        public T Add(T b)
        {
            return NumericOperations<T, T, T, Real<T>>.Add(Value, b);
        }

        public T Divide(T b)
        {
            return NumericOperations<T, T, T, Real<T>>.Div(Value, b);
        }

        public T One
        {
            get { return new Real<T>(1.0); }
        }

        public T Multiply(T b)
        {
            return NumericOperations<T, T, T, Real<T>>.Mul(Value, b);
        }

        #endregion

        #region INumeric<Real<T>> Members

        public int CompareTo(Real<T> other)
        {
            return CompareTo(other.Value);
        }

        public bool Equals(Real<T> other)
        {
            return Equals(Value, other.Value);
        }

        #endregion

        #region INumeric<T> Members

        public bool Equals(T other)
        {
            return Equals(Value, other);
        }

        public int CompareTo(T other)
        {
            return Comparer<T>.Default.Compare(Value, other);
        }

        #endregion

        public override int GetHashCode()
        {
            return Value.GetHashCode();
        }

        public static Real<T> operator +(Real<T> l, Real<T> r)
        {
            return new Real<T>(NumericOperations<T, T, T, Real<T>>.Add(l.Value, r.Value));
        }

        public static Real<T> operator -(Real<T> l, Real<T> r)
        {
            return new Real<T>(NumericOperations<T, T, T, Real<T>>.Sub(l.Value, r.Value));
        }

        public static Real<T> operator *(Real<T> l, Real<T> r)
        {
            return new Real<T>(NumericOperations<T, T, T, Real<T>>.Mul(l.Value, r.Value));
        }

        public static Real<T> operator /(Real<T> l, Real<T> r)
        {
            return new Real<T>(NumericOperations<T, T, T, Real<T>>.Div(l.Value, r.Value));
        }

        public static bool operator ==(Real<T> l, Real<T> r)
        {
            return Equals(l.Value, r.Value);
        }

        public static bool operator >(Real<T> l, Real<T> r)
        {
            return Comparer<T>.Default.Compare(l, r) > 0;
        }

        public static bool operator <(Real<T> l, Real<T> r)
        {
            return Comparer<T>.Default.Compare(l, r) < 0;
        }

        public static bool operator !=(Real<T> l, Real<T> r)
        {
            return !(l == r);
        }

        public static bool operator ==(Real<T> l, T r)
        {
            return Equals(l.Value, r);
        }

        public static bool operator !=(Real<T> l, T r)
        {
            return !(l == r);
        }

        public static implicit operator T(Real<T> o)
        {
            return o.Value;
        }

        public static implicit operator Real<T>(T v)
        {
            return new Real<T>(v);
        }

        public static Real<T> operator +(Real<T> a, Double b)
        {
            return new Real<T>(NumericOperations<T, Double, T, Real<T>>.Add(a.Value, b));
        }

        public Int32 ToInt32()
        {
            return NumericOperations<T, T, T, Real<T>>.ToInt32(Value);
        }

        public Int64 ToInt64()
        {
            return NumericOperations<T, T, T, Real<T>>.ToInt64(Value);
        }

        public Single ToSingle()
        {
            return NumericOperations<T, T, T, Real<T>>.ToSingle(Value);
        }

        public Double ToDouble()
        {
            return NumericOperations<T, T, T, Real<T>>.ToDouble(Value);
        }

        public Decimal ToDecimal()
        {
            return NumericOperations<T, T, T, Real<T>>.ToDecimal(Value);
        }

        public Real<T> Power(double p)
        {
            return NumericOperations<T, T, T, Real<T>>.Power(Value, p);
        }

        internal short ToInt16()
        {
            return NumericOperations<T, T, T, Real<T>>.ToInt16(Value);
        }

        #region IExponential<T> Members

        T IExponential<T>.Power(double exponent)
        {
            return Power(exponent);
        }

        T IExponential<T>.Sqrt()
        {
            return Sqrt();
        }

        public T Log(double newBase)
        {
            return NumericOperations<T, T, T, Real<T>>.Log2(Value, newBase);
        }

        public T Log()
        {
            return NumericOperations<T, T, T, Real<T>>.Log(Value);
        }

        public T Exp()
        {
            return NumericOperations<T, T, T, Real<T>>.Exp(Value);
        }

        #endregion

        #region IExponential<Real<T>> Members


        Real<T> IExponential<Real<T>>.Log(double newBase)
        {
            return Log(newBase);
        }

        Real<T> IExponential<Real<T>>.Log()
        {
            return Log();
        }

        Real<T> IExponential<Real<T>>.Exp()
        {
            return Exp();
        }

        #endregion
    }
}